import sys
import os.path

import wx
import wx.aui
import wx.stc as stc
import wx.lib.newevent

# ---------- My Modules ---------- #
import optionVar
import SuperTextCtrl
import findTextDialog
import fileDragAndDrop

# ---------- Events ---------- #
(EventTabpadOutput, EVT_TABPAD_STATUS) = wx.lib.newevent.NewEvent()
(EventTabpadFileOpened, EVT_TABPAD_FILEOPENED) = wx.lib.newevent.NewEvent()
(EventTabpadPageChanged, EVT_TABPAD_TABCHANGED) = wx.lib.newevent.NewEvent()


class DragTargetToTabpad(fileDragAndDrop.DropTarget):
	def openFile(self, filePath):
		self.window.openFileToNewTab(filePath)
		
	def addDirectory(self, dirPath):
		self.window.printStatus('Drag Directory to FileList instead.')


class TabpadCtrl(wx.aui.AuiNotebook):
	def __init__(self,
				 parent,
				 tabFont='',
				 tabSelectedFont='',
				 editorFont='',
				 normalFileIcon='',
				 pythonIcon='',
				 melIcon='',
				 coding='utf_8'):
		self.parent = parent
		self.Font_TabInActive=tabFont
		self.Font_TabActive=tabSelectedFont
		self.Font_Editor=editorFont
		self.pyIco=pythonIcon
		self.melIco=melIcon
		self.normalFileIco=normalFileIcon
		self.coding=coding
		wx.aui.AuiNotebook.__init__(self, self.parent, -1)
		# ----- Appearance ---- #
		if sys.platform!='darwin':
			self.SetNormalFont(self.Font_TabInActive)
			self.SetSelectedFont(self.Font_TabActive)
		# ----- D&D ----- #
		dt = DragTargetToTabpad(self)
		self.SetDropTarget(dt)
		
		if optionVar.hasOption('OpenedPaths'):
			openedPaths = optionVar.getListOption('OpenedPaths')
		else:
			openedPaths = ['default.py']
		
		self.tabList = []
		for p in openedPaths:
			self.openFileToNewTab(p)
			
		# ----- Bind ----- #
		self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.onPageChanged)
		self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.onCloseTab)
		
	def printStatus(self, msg, append = False):
		evt = EventTabpadOutput(output=msg, append=append)
		wx.PostEvent(self.parent, evt)
		
	def eventFileOpened(self, filePath, coding):
		evt = EventTabpadFileOpened(filePath=filePath, coding=coding)
		wx.PostEvent(self.parent, evt)
		
	def onPageChanged(self, event):
		if len(self.tabList)<=self.GetSelection():
			return None
		coding=self.tabList[self.GetSelection()][4]
		evt = EventTabpadPageChanged(coding=coding)
		wx.PostEvent(self.parent, evt)
		
	def newFile(self, coding=''):
		if coding=='':
			coding=self.coding
			
		# Python or Mel
		dlg = wx.SingleChoiceDialog(
			self, 'Select Code Type', 'The Caption',
			['Python', 'Mel'], 
			wx.CHOICEDLG_STYLE
			)
		
		if dlg.ShowModal() == wx.ID_OK:
			codeType = dlg.GetStringSelection()
		else:
			return None
		dlg.Destroy()
		
		# extension
		if codeType =='Mel':
			ext = 'mel'
		else:
			ext = 'py'
		
		# Decide a new tab title( Not cool code... )
		titles = []
		for i in self.tabList:
			titles.append(i[0])
		num = 1
		title = 'New'+str(num)+'.'+ext
		while title in titles:
			num += 1
			title = 'New'+str(num)+'.'+ext
			
		# Create SuperTextCtrl
		self.printStatus('Add New ' + codeType + ' Tab: ' + title)
		STC = SuperTextCtrl.PythonSTC(self, -1, ext, self.Font_Editor)
		if ext=='mel':
			res = self.AddPage(STC, title, bitmap=self.melIco)
		else:
			res = self.AddPage(STC, title, bitmap=self.pyIco)
			
		if not res:
			self.printStatus('...Failed!', append=True)
			return None
		self.tabList.append((title, '', STC, ext, coding))
		self.SetSelection(len(self.tabList)-1)
		self.printStatus('...Done', append=True)
		STC.EmptyUndoBuffer()
		STC.Colourise(0, -1)
		
		# ----- D&D ----- #
		dt = DragTargetToTabpad(self)
		STC.SetDropTarget(dt)
		
		# line numbers in the margin
		STC.SetMarginType(1, stc.STC_MARGIN_NUMBER)
		STC.SetMarginWidth(1, 25)
		
		# Send Event
		curdir = os.getcwd() # Think it carefully!
		self.eventFileOpened(os.path.join(curdir, title), self.coding)
		
	def openFile(self, coding=''):
		if coding=='':
			coding=self.coding
			
		wildcard = "Script Files (*.py;*.mel)|*.py;*.mel|All files (*.*)|*.*"
		dlg = wx.FileDialog(
			self, message="Choose a file",
			defaultDir=os.getcwd(), 
			defaultFile="",
			wildcard=wildcard,
			style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
			)
		if dlg.ShowModal() == wx.ID_OK:
			# This returns a Python list of files that were selected.
			paths = dlg.GetPaths()
			for p in paths:
				self.openFileToNewTab(p, coding=coding)
		dlg.Destroy()
		
	def openFileToNewTab(self, path, coding=''):
		if coding=='':
			dafaultCoding=self.coding
		else:
			dafaultCoding=coding
			
		if not os.path.isfile(path):
			return None
		title = os.path.basename(path)
		ext = os.path.splitext(path)[1][1:]
		STC = SuperTextCtrl.PythonSTC(self, -1, ext,
									  self.Font_Editor,
									  coding=dafaultCoding)
		
		self.printStatus('Open: ' + path)
		if ext=='mel':
			res = self.AddPage(STC, title, bitmap=self.melIco)
		elif ext=='py':
			res = self.AddPage(STC, title, bitmap=self.pyIco)
		else:
			res = self.AddPage(STC, title, bitmap=self.normalFileIco)
			
		if not res:
			self.printStatus('....Failed!', append=True)
			return None
		returnedCoding = STC.LoadFile(path, coding=coding)
		self.tabList.append((title, path, STC, ext, returnedCoding))
		self.SetSelection(len(self.tabList)-1)
		self.printStatus('....Done', append=True)
		STC.EmptyUndoBuffer()
		STC.Colourise(0, -1)
		
		# ----- D&D ----- #
		dt = DragTargetToTabpad(self)
		STC.SetDropTarget(dt)
		
		# line numbers in the margin
		STC.SetMarginType(1, stc.STC_MARGIN_NUMBER)
		STC.SetMarginWidth(1, 25)
		
		# Send Event
		self.eventFileOpened(path, returnedCoding)
		
	def UpdateTabList(self,id, title, path, STC, ext, coding):
		self.tabList[id]=(title, path, STC, ext, coding)
		self.SetPageText(id, title)
		
	def getCurrentFilename(self):
		currentTabNum = self.GetSelection()
		return self.tabList[currentTabNum][0]
		
	def getCurrentExt(self):
		currentTabNum = self.GetSelection()
		return self.tabList[currentTabNum][3]
	
	def saveAllTab(self):
		for i in range(0, len(self.tabList)):
			self.SetSelection(i)
			self.saveTab(self.tabList[i][1])
			
	def saveTab(self, path=''):
		currentTabNum = self.GetSelection()
		currentFilename = self.tabList[currentTabNum][0]
		currentPath = self.tabList[currentTabNum][1]
		currentExt = self.tabList[currentTabNum][3]
		currentTitle = self.GetPageText(currentTabNum)
		currentSTC = self.tabList[currentTabNum][2]
		currentCoding = self.tabList[currentTabNum][4]
		if path !='':
			currentPath = path
			self.UpdateTabList(currentTabNum,
							   os.path.basename(currentPath),
							   currentPath,
							   currentSTC,
							   os.path.splitext(currentPath)[1][1:],
							   currentCoding)
		if currentPath =='':
			#Need a file path
			if currentExt=='mel':
				wildcard = "Mel Source (*.mel)|*.mel|" \
						   "All files (*.*)|*.*"
			else:
				wildcard = "Python source (*.py)|*.py|"\
						   "All files (*.*)|*.*"
			dlg = wx.FileDialog(
				self, message="Save file as",
				defaultDir=os.getcwd(), 
				defaultFile=currentTitle,
				wildcard=wildcard,
				style=wx.SAVE | wx.CHANGE_DIR
				)
			if dlg.ShowModal() == wx.ID_OK:
				paths = dlg.GetPaths()
				currentPath = paths[0]
			dlg.Destroy()
			if currentPath =='':
				return None
			else:
				# Update tab info
				self.UpdateTabList(currentTabNum,
								   os.path.basename(currentPath),
								   currentPath,
								   currentSTC,
								   currentExt,
								   currentCoding)
		self.printStatus('Save: ' + currentPath)
		
		res = currentSTC.SaveFile(currentPath, coding = currentCoding)
		if res:
			self.printStatus('....Done', append=True)
			currentSTC.SetSavePoint()
		else:
			self.printStatus('....Failed!', append=True)
			
	def saveTabAs(self):
		currentExt = self.getCurrentExt()
		if currentExt=='mel':
			wildcard = "Mel Source (*.mel)|*.mel|" \
						"Python source (*.py)|*.py|"\
						"All files (*.*)|*.*"
		else:
			wildcard = "Python source (*.py)|*.py|"\
					   "Mel Source (*.mel)|*.mel|" \
					   "All files (*.*)|*.*"
		dlg = wx.FileDialog(
			self, message="Save as",
			defaultDir=os.getcwd(), 
			defaultFile=self.getCurrentFilename(),
			wildcard=wildcard,
			style=wx.SAVE | wx.CHANGE_DIR
			)
		if dlg.ShowModal() == wx.ID_OK:
			# This returns a Python list of files that were selected.
			paths = dlg.GetPaths()
			for p in paths:
				self.saveTab(p)
		dlg.Destroy()
		
	def undo(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Undo()
	
	def redo(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Redo()
	
	def cut(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Cut()
	
	def copy(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Copy()
	
	def paste(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Paste()
	
	def clear(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.Clear()
	
	def selectAll(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.SelectAll()
		
	def find(self):
		dlg = findTextDialog.FindDialog(self, -1)
		if dlg.ShowModal() == wx.ID_OK:
			self.searchWord = dlg.searchWord
			self.option_upperLower= dlg.option_upperLower
			self.direction = dlg.direction
			if dlg.mode == 'SearchFromHead':
				self.SearchFromHead(self.searchWord)
			elif dlg.mode == 'SearchNext':
				self.SearchNext(self.searchWord, self.direction)
		dlg.Destroy()
		
	def findNext(self):
		self.SearchNext(self.searchWord, self.direction)
		
	def SearchFromHead(self, word):
		self.printStatus('Search Word: '+word)
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		currentSTC.GotoPos(0)
		currentSTC.SearchAnchor()
		currentSTC.SearchNext( wx.stc.STC_FIND_REGEXP, word)
		
	def SearchNext(self, word, direction):
		if word == '':
			return None
		self.printStatus('Search Word: '+word)
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		if direction == 'Down':
			currentPos = currentSTC.GetCurrentPos()
			currentSTC.GotoPos(currentPos+len(word))
			currentSTC.SearchAnchor()
			res =currentSTC.SearchNext( wx.stc.STC_FIND_REGEXP, word)
			if res==-1:
				currentSTC.GotoPos(0)
				currentSTC.SearchAnchor()
				currentSTC.SearchNext( wx.stc.STC_FIND_REGEXP, word)
		elif direction == 'Up':
			currentSTC.SearchAnchor()
			res =currentSTC.SearchPrev( wx.stc.STC_FIND_REGEXP, word)
			if res==-1:
				currentSTC.DocumentEnd()
				currentSTC.SearchAnchor()
				currentSTC.SearchPrev( wx.stc.STC_FIND_REGEXP, word)
				
	def getSelectedText(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		return currentSTC.GetSelectedText()
	
	def getText(self):
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		return currentSTC.GetText()
	
	def onCloseTab(self, event):
		self.closeTab()
		
	def closeTab(self):
		currentTabNum = self.GetSelection()
		currentTitle = self.GetPageText(currentTabNum)
		self.printStatus('Close tab: ' + currentTitle)
		ed = self.GetPage(currentTabNum)
		ed.Close()
		del self.tabList[currentTabNum]
		self.printStatus('....Done', append=True)
		
	def close(self):
		currentPaths = []
		for i in range(0, len(self.tabList)):
			self.SetSelection(i)
			# if modified
			currentTitle = self.tabList[i][0]
			currentSTC = self.tabList[i][2]
			if currentSTC.GetModify():
				print str(i)+': '+currentTitle+' Modified'
				dlg = wx.MessageDialog(self, 
									   (currentTitle
										+ ' is modified, Save before Exit?'),
									   'Confirm',
									   wx.YES_NO | wx.YES_DEFAULT | wx.CANCEL | wx.ICON_QUESTION
									   )
				res = dlg.ShowModal()
				if res == wx.ID_YES:
					dlg.Destroy()
					self.saveTab(self.tabList[i][1])
				elif res == wx.ID_CANCEL:
					dlg.Destroy()
					return None
				else:
					dlg.Destroy()
			currentPath = self.tabList[i][1]
			if currentPath != '':
				currentPaths.append(currentPath)
		optionVar.saveOption('OpenedPaths', currentPaths)
		
	# ----- Appearance ----- #
	def GetFont(self):
		return self.Font_Editor
	
	def SetFont(self, font):
		for t in self.tabList:
			t[2].SetFont(font)
		self.Font_Editor=font
		
	def GetCurrentCoding(self):
		"""
		This function doesn't work. Everything will return UTF-8.
		Actually Scintilla can use only UTF-8?
		Very poor support of Character code.
		"""
		currentTabNum = self.GetSelection()
		currentSTC = self.tabList[currentTabNum][2]
		code = currentSTC.GetCodePage()
		if code == 65001:
			return 'UTF-8'
		elif code == 1:#1
			return 'DBCS'
		elif code == 0:#0
			return 'disable DBCS support'
		else:
			return code
